package com.ls.config.shiro;

import com.ls.entity.SysPermission;
import com.ls.service.ISysPermissionService;
import com.ls.utils.redis.RedisClient;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.DelegatingFilterProxy;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.ls.utils.redis.RedisKey.LIST_FIELD;
import static com.ls.utils.redis.RedisKey.SYS_PERMISSION_KEY;


/**
 * @ClassName ShiroConfig
 * @Description 权限框架相关配置
 * @Author YangLei
 * @Date 2019/5/7 10:30
 * @Version 1.0
 **/

@Configuration
public class ShiroConfig {
    private static Logger LOGGER = LoggerFactory.getLogger(ShiroConfig.class);

    @Resource
    private ISysPermissionService sysPermissionService;

    @Resource
    private RedisClient redisClient;

    /**
     * 注入ShiroRealm
     */
    @Bean
    public ShiroRealm shiroRealm() {
        return new ShiroRealm();
    }

    /**
     * 注入securityManager
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(shiroRealm());
        return manager;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        //1 定义shiroFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //2 设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //设置默认登录的url
        shiroFilterFactoryBean.setLoginUrl("/login/goLogin");
        shiroFilterFactoryBean.setUnauthorizedUrl("/login/unauthorized");

        //3 查询系统中所有权限并交给shiro框架
        Map<String, String> result = new LinkedHashMap<>();
        // 静态资源放行
        result.put("/resources/**", "anon");
        result.put("/druid/**", "anon");
        result.put("/static/**", "anon");
        result.put("/swagger/**", "anon");
        result.put("/swagger-ui.html", "anon");
        result.put("/swagger-resources/**", "anon");
        result.put("/webjars/**", "anon");
        result.put("/v2/api-docs", "anon");
        result.put("/index.html", "anon");
        result.put("/order.html", "anon");
        result.put("/css/**", "anon");
        result.put("/fonts/**", "anon");
        result.put("/img/**", "anon");
        result.put("/js/**", "anon");
        result.put("/favicon.ico*", "anon");

        //Nginx检查页面
        result.put("/check.html", "anon");

        //注销
        result.put("/login/logout", "logout");
        result.put("/login/logout", "anon");
        //公钥查询
        result.put("/login/getPublicKey", "anon");
        //用户菜单查询
        result.put("/user/getUserMenuList", "anon");

        //拦截到登录（返回json，前端控制跳转到登录页面）
        result.put("/login/goLogin", "anon");
        //用户名密码登录
        result.put("/login/login", "anon");
        //商家离线登录
        result.put("/login/loginForOffLine", "anon");
        result.put("/login", "anon");
        //登录验证码相关
        result.put("/login/getVerifyCodeImage", "anon");

        //druid连接池相关
        result.put("/druid/*", "anon");
        result.put("/Default", "anon");


        //3 登录后需要有权限才能访问的页面
        List<SysPermission> permissions = redisClient.getList(SYS_PERMISSION_KEY, LIST_FIELD, SysPermission.class);
        if (permissions == null || permissions.size() == 0) {
            permissions = sysPermissionService.loadAllPermissions();
            redisClient.save(SYS_PERMISSION_KEY, LIST_FIELD, permissions);
        }

        //此处不能注释，！！！！！！！！！！！！！！！！！！！！！！！！！！！！！！
        for (SysPermission permission : permissions) {
            if (permission.getResources() == null || permission.getSn() == null) {
                continue;
            }
            //数据库中接口路径
            String resource = permission.getResources();
            //数据库中sn拼接
            String perm = "perms[" + permission.getSn() + "]";
            result.put(resource, perm);
        }

        //4 其他接口一律拦截，登录即可访问
        //这行代码必须放在所有权限设置的最后，不然会导致所有 url 都被拦截
        result.put("/**", "authc");
        //过滤为空的
        Set<String> keys = result.keySet();
        Map<String, String> map = new LinkedHashMap<>();
        for (String key : keys) {
            if (!StringUtils.isEmpty(key) && !StringUtils.isEmpty(result.get(key))) {
                map.put(key, result.get(key));
            }
        }
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        LOGGER.info("Project All permission:{}", result);
        return shiroFilterFactoryBean;
    }


    /**
     * 注册AuthorizationAttributeSourceAdvisor
     * 如果要开启注解@RequiresRoles等注解，必须添加
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager manager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(manager);
        return advisor;
    }


    @Bean
    public FilterRegistrationBean delegatingFilterProxy() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");
        filterRegistrationBean.setFilter(proxy);
        return filterRegistrationBean;
    }
}
